package com.titan.core.utils.db;

import java.math.BigDecimal;
import java.math.BigInteger;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author 周成功
 * @email 86898837@qq.com
 * @date 2020年02月14日
 */
public class RecordSet {
	private int columnCount = 0;          // 列数
	private int rowCount = 0;             // 行数
	private int cursor = 0;               // 当前行数
	private HashMap columnIndex = null;   // 列名与列号的对应关系
	private String[] columnName = null;   // 列名
	private List data = null;             // 存储结果数据

	/**
	 * @see java.lang.Object#Object()
	 */
	public RecordSet() {
		super();
	}

	/**
	 * Method RecordSet.
	 * @param rs
	 * @throws Exception
	 */
	public RecordSet(ResultSet rs) throws SQLException {
		setData(rs);
	}

	/**
	 * Method RecordSet.
	 * @param rs
	 * @param beginRow
	 * @throws Exception
	 */
	public RecordSet(ResultSet rs, int beginRow) throws SQLException {
		setData(rs, beginRow);
	}

	/**
	 * Method RecordSet.
	 * @param rs
	 * @param beginRow
	 * @param rowNum
	 * @throws Exception
	 */
	public RecordSet(ResultSet rs, int beginRow, int rowNum) throws SQLException {
		setData(rs, beginRow, rowNum);
	}

	/**
	 * Method clear.
	 */
	public void clear() {
		columnCount = 0; //列数
		rowCount = 0; //行数
		cursor = 0; //当前行数
        columnName = null; //列名
		if(columnIndex!=null) {//列名与列号的对应关系
		    columnIndex.clear();
	        columnIndex = null; 
		}
		if(data!=null) {//存储结果数据
		    data.clear();
	        data = null; 
		}
	}

	/**
	 * Method setData.
	 * @param rs
	 * @throws Exception
	 */
	public void setData(ResultSet rs) throws SQLException {
		setData(rs, 1, -1);
	}

	/**
	 * Method setData.
	 * @param rs
	 * @param beginRow
	 * @throws Exception
	 */
	public void setData(ResultSet rs, int beginRow) throws SQLException {
		setData(rs, beginRow, -1);
	}

	/**
	 * Method setData.
	 * @param rs
	 * @param beginRow
	 * @param rowNum
	 * @throws Exception
	 */
	public void setData(ResultSet rs, int beginRow, int rowNum) throws SQLException {
		List vRowData = null;
		ResultSetMetaData rsmd = null;
		clear(); //清除原有数据

		//取列数
        rsmd = rs.getMetaData();
        columnCount = rsmd.getColumnCount();

		columnName = new String[columnCount];
		columnIndex = new HashMap();
		data = new ArrayList();

		//保存列名
        for (int i = 0; i < columnCount; i++) {
            columnIndex.put( (rsmd.getColumnName(i + 1)).toUpperCase(), new Integer(i + 1) );
            columnName[i] = rsmd.getColumnName(i + 1);
        }

        //跳过起始行前边的记录
        for (int i = 0; i < beginRow - 1; i++) {
            rs.next();
        }

        //保存结果集
        while (rs.next() && (rowNum < 0 || rowNum > rowCount)) {
            rowCount++;
            vRowData = new ArrayList();
            for (int i = 0; i < columnCount; i++) {
                Object object = rs.getObject(i + 1);
                if((object!=null)&&(object.getClass().getName().indexOf("CLOB")>0)) {
                    object = rs.getString(i + 1);
                }
                vRowData.add(object);
            }
            data.add(vRowData);
        }
	}

	/**
	 * Method getColumnName.
	 * @param columnNum
	 * @return String
	 */
	public String getColumnName(int columnNum) {
		return columnName[columnNum - 1];
	}

	/**
	 * Method getRowCount.
	 * @return int
	 */
	public int getRowCount() {
		return rowCount;
	}

	/**
	 * Method getColumnCount.
	 * @return int
	 */
	public int getColumnCount() {
            return columnCount;
	}

	public int getColumnIndex(String columnName) throws Exception{
            Integer iIndex = (Integer) (columnIndex.get(columnName.toUpperCase()));
            if (iIndex == null){
                throw new Exception("error column name : "+columnName);
            }
            return iIndex.intValue();
	}

	/**
	 * Method getCursor.
	 * @return int
	 */
	public int getCursor() {
		return cursor;
	}

    /**
     * Method moveTo.
     * @param cursor
     * @return boolean
     */
    public void moveInit() {
        this.cursor = 0;
    }

	/**
	 * Method moveTo.
	 * @param cursor
	 * @return boolean
	 */
	public boolean moveTo(int cursor) {
		if (cursor > 0 && cursor <= rowCount) {
			this.cursor = cursor;
			return true;
		}
		return false;
	}

	/**
	 * Method moveFirst.
	 * @return boolean
	 */
	public boolean moveFirst() {
		return moveTo(1);
	}

	/**
	 * Method moveLast.
	 * @return boolean
	 */
	public boolean moveLast() {
		return moveTo(rowCount);
	}

	/**
	 * Method moveNext.
	 * @return boolean
	 */
	public boolean moveNext() {
		return moveTo(cursor + 1);
	}

	/**
	 * Method movePrev.
	 * @return boolean
	 */
	public boolean movePrev() {
		return moveTo(cursor - 1);
	}

	public Object[] getColumnObject(int columnNum){
		Object[] aobjColumn = new Object[rowCount];

		for (int i=0;i<rowCount;i++){
			aobjColumn[i]=getObject(i+1,columnNum);
		}

		return aobjColumn;
	}

	public Object[] getColumnObject(String columnName)throws Exception{
		return getColumnObject(getColumnIndex(columnName));
	}

	public int[] getColumnInt(int columnNum){
		int[] aiColumn = new int[rowCount];

		for (int i=0;i<rowCount;i++){
			aiColumn[i]=getInt(i+1,columnNum);
		}

		return aiColumn;
	}

	public int[] getColumnInt(String columnName)throws Exception{
		return getColumnInt(getColumnIndex(columnName));
	}

	public String[] getColumnString(int columnNum)throws Exception{
		String[] astrColumn = new String[rowCount];

		for (int i=0;i<rowCount;i++){
			astrColumn[i]=getString(i+1,columnNum);
		}

		return astrColumn;
	}

	public String[] getColumnString(String columnName)throws Exception{
		return getColumnString(getColumnIndex(columnName));
	}

	public long[] getColumnLong(int columnNum)throws Exception{
		long[] alColumn = new long[rowCount];

		for (int i=0;i<rowCount;i++){
			alColumn[i]=getLong(i+1,columnNum);
		}

		return alColumn;
	}

	public long[] getColumnlong(String columnName)throws Exception{
		return getColumnLong(getColumnIndex(columnName));
	}

	public double[] getColumnDouble(int columnNum)throws Exception{
		double[] adColumn = new double[rowCount];

		for (int i=0;i<rowCount;i++){
			adColumn[i]=getDouble(i+1,columnNum);
		}

		return adColumn;
	}

	public double[] getColumnDouble(String columnName)throws Exception{
		return getColumnDouble(getColumnIndex(columnName));
	}

	public float[] getColumnFloat(int columnNum)throws Exception{
		float[] afColumn = new float[rowCount];

		for (int i=0;i<rowCount;i++){
			afColumn[i]=getFloat(i+1,columnNum);
		}

		return afColumn;
	}

	public float[] getColumnFloat(String columnName)throws Exception{
		return getColumnFloat(getColumnIndex(columnName));
	}

	public BigDecimal[] getColumnBigDecimal(int columnNum)throws Exception{
		BigDecimal[] abdColumn = new BigDecimal[rowCount];

		for (int i=0;i<rowCount;i++){
			abdColumn[i]=getBigDecimal(i+1,columnNum);
		}

		return abdColumn;
	}

	public BigDecimal[] getColumnBigDecimal(String columnName)throws Exception{
		return getColumnBigDecimal(getColumnIndex(columnName));
	}

	/**
	 * Method getObject.
	 * @param rowNum
	 * @param columnNum
	 * @return Object
	 */
	public Object getObject(int rowNum, int columnNum) {
		if (rowNum < 1 || rowNum > rowCount) {
			return null;
		}
		if (columnNum < 1 || columnNum > columnCount) {
			return null;
		}
		Object object = ((List) (data.get(rowNum - 1))).get(columnNum - 1);
		return object;
	}

	/**
	 * Method getObject.
	 * @param columnNum
	 * @return Object
	 */
	public Object getObject(int columnNum) {
		return getObject(cursor, columnNum);
	}

	/**
	 * Method getObject.
	 * @param rowNum
	 * @param columnName
	 * @return Object
	 */
	public Object getObject(int rowNum, String columnName) throws Exception{
		return getObject(rowNum, getColumnIndex(columnName));
	}

	/**
	 * Method getObject.
	 * @param columnName
	 * @return Object
	 */
	public Object getObject(String columnName) throws Exception{
		return getObject(cursor, columnName);
	}

	/**
	 * Method getString.
	 * @param rowNum
	 * @param columnNum
	 * @return String
	 */
	public String getString(int rowNum, int columnNum) throws Exception {
		Object obj = getObject(rowNum, columnNum);

		if (obj == null)
			return "";

		String strResult = null;
		if (obj instanceof String) {
			return (String)obj;
		} else if (obj instanceof byte[]) {
			byte[] abyteResult = (byte[]) obj;
                        ////////////////////////////////////////////////////////////////////
                        // 2005年09月01日  周成功  修改字符集编码
			//strResult = new String(abyteResult, "GBK");
                        strResult = new String(abyteResult);
                        ////////////////////////////////////////////////////////////////////
		} else {
			strResult = obj.toString();
		}
		return strResult;
	}

	/**
	 * Method getString.
	 * @param columnNum
	 * @return String
	 */
	public String getString(int columnNum) throws Exception {
		return getString(cursor, columnNum);
	}

	/**
	 * Method getString.
	 * @param rowNum
	 * @param columnName
	 * @return String
	 */
	public String getString(int rowNum, String columnName) throws Exception {
		return getString(rowNum, getColumnIndex(columnName));
	}

	/**
	 * Method getString.
	 * @param columnName
	 * @return String
	 */
	public String getString(String columnName) throws Exception {
		return getString(cursor, columnName);
	}

	/**
	 * Method getLong.
	 * @param rowNum
	 * @param columnNum
	 * @return long
	 */
	public long getLong(int rowNum, int columnNum) {
		Object obj = getObject(rowNum, columnNum);
		if (obj == null) {
			return 0;
        } else if (obj instanceof Integer){
            Integer result = (Integer)obj;
            return result.longValue();
        } else if (obj instanceof Double){
            Double result = (Double)obj;
            return result.longValue();
		} else if(obj instanceof BigInteger) {
            BigInteger result =(BigInteger)obj;
            return result.longValue();
		} else {
    		BigDecimal result = (BigDecimal) obj;
    		return result.longValue();
		}
	}

	/**
	 * Method getLong.
	 * @param columnNum
	 * @return long
	 */
	public long getLong(int columnNum) {
		return getLong(cursor, columnNum);
	}

	/**
	 * Method getLong.
	 * @param rowNum
	 * @param columnName
	 * @return long
	 */
	public long getLong(int rowNum, String columnName) throws Exception{
		return getLong(rowNum, getColumnIndex(columnName));
	}

	/**
	 * Method getLong.
	 * @param columnName
	 * @return long
	 */
	public long getLong(String columnName)throws Exception {
		return getLong(cursor, columnName);
	}

	/**
	 * Method getInt.
	 * @param rowNum
	 * @param columnNum
	 * @return int
	 */
	public int getInt(int rowNum, int columnNum) {
		Object obj = getObject(rowNum, columnNum);
		if (obj == null){
			return 0;
		} else if (obj instanceof Integer){
			Integer result = (Integer)obj;
			return result.intValue();
        } else if (obj instanceof Double){
            Double result = (Double)obj;
            return result.intValue();
        } else if(obj instanceof BigInteger) {
            BigInteger result =(BigInteger)obj;
            return result.intValue();
		} else {
			BigDecimal result = (BigDecimal) obj;
			return result.intValue();
		}
	}

	/**
	 * Method getInt.
	 * @param columnNum
	 * @return int
	 */
	public int getInt(int columnNum) {
		return getInt(cursor, columnNum);
	}

	/**
	 * Method getInt.
	 * @param rowNum
	 * @param columnName
	 * @return int
	 */
	public int getInt(int rowNum, String columnName) throws Exception{
		return getInt(rowNum, getColumnIndex(columnName));
	}

	/**
	 * Method getInt.
	 * @param columnName
	 * @return int
	 */
	public int getInt(String columnName) throws Exception{
		return getInt(cursor, columnName);
	}


	/**
	 * Method getDouble.
	 * @param rowNum
	 * @param columnNum
	 * @return double
	 */
	public double getDouble(int rowNum, int columnNum) {
		Object obj = getObject(rowNum, columnNum);
        if (obj == null){
            return 0;
        } else if (obj instanceof Integer){
            Integer result = (Integer)obj;
            return result.doubleValue();
        } else if (obj instanceof Double){
            Double result = (Double)obj;
            return result.doubleValue();
        } else if(obj instanceof BigInteger) {
            BigInteger result =(BigInteger)obj;
            return result.doubleValue();
        } else {
            BigDecimal result = (BigDecimal) obj;
            return result.doubleValue();
        }
	}

	/**
	 * Method getDouble.
	 * @param columnNum
	 * @return double
	 */
	public double getDouble(int columnNum) {
		return getDouble(cursor, columnNum);
	}

	/**
	 * Method getDouble.
	 * @param rowNum
	 * @param columnName
	 * @return double
	 */
	public double getDouble(int rowNum, String columnName) throws Exception {
		return getDouble(rowNum, getColumnIndex(columnName));
	}

	/**
	 * Method getDouble.
	 * @param columnName
	 * @return double
	 */
	public double getDouble(String columnName) throws Exception{
		return getDouble(cursor, columnName);
	}

	/**
	 * Method getFloat.
	 * @param rowNum
	 * @param columnNum
	 * @return float
	 */
	public float getFloat(int rowNum, int columnNum) {
		Object obj = getObject(rowNum, columnNum);
        if (obj == null){
            return 0;
        } else if (obj instanceof Integer){
            Integer result = (Integer)obj;
            return result.floatValue();
        } else if (obj instanceof Double){
            Double result = (Double)obj;
            return result.floatValue();
        } else if(obj instanceof BigInteger) {
            BigInteger result =(BigInteger)obj;
            return result.floatValue();
        } else {
            BigDecimal result = (BigDecimal) obj;
            return result.floatValue();
        }
	}

	
	/**
	 * Method getFloat.
	 * @param columnNum
	 * @return float
	 */
	public float getFloat(int columnNum) {
		return getFloat(cursor, columnNum);
	}

	/**
	 * Method getFloat.
	 * @param rowNum
	 * @param columnName
	 * @return float
	 */
	public float getFloat(int rowNum, String columnName) throws Exception {
		return getFloat(rowNum, getColumnIndex(columnName));
	}

	/**
	 * Method getFloat.
	 * @param columnName
	 * @return float
	 */
	public float getFloat(String columnName) throws Exception{
		return getFloat(cursor, columnName);
	}

	/**
	 * Method getBigDecimal.
	 * @param rowNum
	 * @param columnNum
	 * @return BigDecimal
	 */
	public BigDecimal getBigDecimal(int rowNum, int columnNum) {
		Object obj = getObject(rowNum, columnNum);
		if (obj == null)
			return null;
		return (BigDecimal) obj;
	}

	/**
	 * Method getBigDecimal.
	 * @param columnNum
	 * @return BigDecimal
	 */
	public BigDecimal getBigDecimal(int columnNum) {
		return getBigDecimal(cursor, columnNum);
	}

	/**
	 * Method getBigDecimal.
	 * @param rowNum
	 * @param columnName
	 * @return BigDecimal
	 */
	public BigDecimal getBigDecimal(int rowNum, String columnName) throws Exception{
		return getBigDecimal(rowNum, getColumnIndex(columnName));
	}

	/**
	 * Method getBigDecimal.
	 * @param columnName
	 * @return BigDecimal
	 */
	public BigDecimal getBigDecimal(String columnName)throws Exception {
		return getBigDecimal(cursor, columnName);
	}

    /**
     * 删除一条记录
     * @param rowNum int
     * @throws Exception
     */
    public void removeRow(int rowNum) throws Exception{
        if(rowCount>0){
            data.remove(rowNum);
            rowCount =data.size();
            if(cursor>rowCount){
                cursor =rowCount;
            }
        }
    }
    

    public Object get() {
        return get(cursor);
    }
    public Object get(int rowNum) {
        if (rowNum < 1 || rowNum > rowCount) {
            return null;
        }
        return data.get(rowNum - 1);
    }
    
    public void add(RecordSet set) {
        while(set.moveNext()) {
            Object obj = set.get();
            if(obj!=null) {
                addObject(obj);
            }
        }        
    }
    
    /**
     * 增加记录内容
     * @param obj Object
     * @throws Exception
     */
    public void addObject(Object obj) {
        if(data==null)  data =new ArrayList();
        data.add(obj);
        rowCount ++;
    }
    
    
    /** 将指定行转换成Map对象 */
    public Map toMap(int rowNum) throws Exception {
        Map data =new HashMap();
        for (int i = 0; i < columnName.length; i++) {
            data.put(columnName[i].toUpperCase(), this.getObject(rowNum, columnName[i]));
        }
        return data;
    }


    /** 将当前行转化成Map对象 */
    public Map toMap() throws Exception {
        return toMap(cursor);
    }

    
    /** 将所有数据转换成Map数据 */
    public Map[] toMaps() throws Exception {
        Map[] items =new Map[rowCount];
        for (int i = 0; i < rowCount; i++) {
            items[i] = toMap(i+1);
        }
        return items;
    }
    
    
    public String toString() {
        StringBuffer buffer =new StringBuffer(1024);
        for (int i = 1; i <= rowCount; i++) {
            buffer.append("["+i+"]");
            for (int j = 0; j < columnName.length; j++) {
                try {
                    buffer.append("["+columnName[j]+"="+this.getObject(i, columnName[j])+"]");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            buffer.append("\n");
        }
        return buffer.toString();
    }
}

